package com.yesun.task.pipeline.common;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mchange.io.FileUtils;
import com.yesun.task.pipeline.domain.dto.JobDto;
import com.yesun.task.pipeline.quartz.JobSchedule;
import com.yesun.task.pipeline.quartz.QuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.SchedulerException;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author yesun
 * @Descritpion
 * @Date 2023/8/17 16:46
 * @Version 1.0
 **/
@Slf4j
public class JobUtil {

    public static List<JobDto> LIST_JOBS = new ArrayList<>();
    static SimpleDateFormat shortSdf = new SimpleDateFormat("yyyyMMdd");

    //初始化JOB
    public static void initJobFromConf(String basePath, String conf) {
        loadFromFile(basePath, conf);
        //启动conf监听，修改时，重新加载文件
        String p = basePath + "/" + conf.substring(0, conf.lastIndexOf("/"));
        log.debug("监听conf：" + p);
        Path path = Paths.get(p);
        try {
            WatchService watcher = FileSystems.getDefault().newWatchService();
            path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        WatchKey key = null;
                        while((key = watcher.take()) != null) {
                            //这里有个隐藏BUG，为什么会执行两次
                            for(WatchEvent<?> event : key.pollEvents()) {
                                if(event.kind() == StandardWatchEventKinds.OVERFLOW) {
                                    continue;
                                }
                                Path filename = (Path)event.context();
                                log.info("文件已更新，重新加载！");
                                try {
                                    JobSchedule.clear();
                                    //重新加载
                                    loadFromFile(basePath, conf);
                                    //必须reset，否则后面监听不到
                                } catch (SchedulerException e) {
                                    e.printStackTrace();
                                }
                            }
                            //reset 重新监听后面
                            key.reset();
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.setName("ConfigListenerThread");
            t.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void loadFromFile(String basePath, String conf) {
        //初始化Task，从配置文件中载入，支持动态配置新JOB，暂时先写死
        try {
            String json = FileUtils.getContentsAsString(new File(basePath + "/" + conf));
            if (StringUtils.isNotBlank(json)) {
                JSONArray jsonArray = JSONObject.parseObject(json)
                        .getJSONObject("conf")
                        .getJSONArray("jobs");

                //解析job配置信息
                jsonArray.stream().forEach(line -> {
//                    log.info(line.toString());
                    JSONObject job = JSONObject.parseObject(line.toString());
                    Map<String, JobDto> map = new HashMap<>();
                    JSONObject objMap = job.getJSONObject("map");
                    Map params = new HashMap<>();
                    if (objMap != null) {
                        //map中的属性是动态的
                        JSONArray jsonMap = objMap.getJSONArray("list");
                        //利用list有序，传递这几个需要保持顺序的参数
                        List<String> list = new ArrayList<>();
                        if (jsonMap != null && jsonMap.size() > 0) {
                            //遍历解析，加载到map
                            jsonMap.stream().forEach(att -> {
                                list.add(basePath + att.toString().replace("{date}", shortSdf.format(new Date())));
                            });
                            params.put("params", list);
                        }
                    }

                    String cron = "";
                    if(StringUtils.isNotEmpty(job.getString("cron"))) {
                        cron = job.getString("cron");
                    }
                    //更简洁的corn
                    if(StringUtils.isNotEmpty(job.getString("delay"))) {
                        int delay = job.getIntValue("delay");
                        //change to corn
                        Calendar cal = Calendar.getInstance();
                        cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE) + delay);
                        cal.set(Calendar.SECOND, 0);
                        cron = CronUtil.getCron(cal.getTime());
                    }

                    log.info(cron + " 执行：" + job.getString("name"));

                    JobDto jobDto = new JobDto(job.getString("name"), job.getString("type"), job.getString("tag"), cron, job.getString("dependancyJobName"), params);
                    map.put("job", jobDto);
                    LIST_JOBS.add(jobDto); //保存静态变量，方便其他地方统计

                    //添加JOB
                    try {
                        JobSchedule.addJob(job.getString("name"), map, cron, QuartzJob.class);
                    } catch (SchedulerException e) {
                        e.printStackTrace();
                    }
                });
            }
        } catch(IOException e){
            e.printStackTrace();
        }
    }

}



